home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 16
/
Aminet 16 (1996)(GTI - Schatztruhe)[!][Dec 1996].iso
/
Aminet
/
dev
/
mui
/
MCC_Tron0_7.lha
/
MCC_Tron
/
Source
/
MUI
/
mccheader.c
next >
Wrap
C/C++ Source or Header
|
1996-10-25
|
12KB
|
497 lines
/*****************************************************************************
This code serves as a basis for writing a library-based MUI custom class
(xyz.mcc) and its preferences editor (xyz.mcp).
You need to define a few things in your main source file, then include
this file and then continue with your classes methods. The order is
important, mccheader.c must be the first code-generating module.
Things to be defined before mccheader.c is included:
(1) UserLibID - version string for your class. must follow normal $VER: string conventions.
(2) VERSION - version number of the class. must match the one given in the $VER: string.
(3) REVISION - revision number of the class. must match the one given in the $VER: string.
(4) CLASS - Name of your class, ".mcc" or ".mcp" must always be appended.
(5) SUPERCLASS - superclass of your class.
(6) struct Data - instance data structure.
(7) _Dispatcher - your dispatcher function.
(8) SUPERCLASSP - Superclass of the preferences class, must be MUIC_Mccprefs or a subclass.
(9) struct DataP - instance data structure of preferences class.
(10) _DispatcherP - dispatcher for the preferences class.
Items (1) to (4) must always be defined. If you create a stand-alone
custom class (*.mcc) without preferences editor, also define (5), (6)
and (7). Name your class and the resulting ouptut file "Myclass.mcc".
If you create a preferences class (*.mcp) for a custom class, define
(8), (9) and (10) instead of (5), (6) and (7). Name your class and the
resulting output file "Myclass.mcp".
If you create a custom class with included preferences editor, define
all the above. Note that in this case, the name of your class and the
resulting output file is always "Myclass.mcc". MUI will automatically
recognize that there's also a "Myclass.mcp" included. Having a builtin
preferences class reduces the need for a second file but increases the
size and memory consuption of the class.
If your class needs custom initialization (e.g. opening other
libraries), you can define
ClassInit
ClassExit
to point to custom functions. These functions need to have the prototypes
BOOL ClassInitFunc(struct Library *base);
VOID ClassExitFunc(struct Library *base);
and will be called right after the class has been created and right
before the class is being deleted. If your init func returns FALSE,
the custom class will be unloaded immediately.
Define the minimum version of muimaster.libray in MASTERVERSION. If you
don't define MASTERVERSION, it will default to MUIMASTER_VMIN from the
mui.h include file.
This code automatically defines and initializes the following variables:
struct Library *MUIMasterBase;
struct Library *SysBase;
struct Library *UtilityBase;
struct Library *DOSBase;
struct Library *GfxBase;
struct Library *IntuitionBase;
struct Library *MUIClassBase; /* your classes library base */
struct MUI_CustomClass *ThisClass; /* your custom class */
struct MUI_CustomClass *ThisClassP; /* your preferences class */
Example: Myclass.c
#define CLASS MUIC_Myclass // name of class, e.g. "Myclass.mcc"
#define SUPERCLASS MUIC_Area // name of superclass
struct Data
{
LONG MyData;
struct Foobar MyData2;
// ...
};
#define UserLibID "$VER: Myclass.mcc 17.53 (11.11.96)"
#define VERSION 17
#define REVISION 53
#include "mccheader.c"
ULONG ASM SAVEDS _Dispatcher(REG(a0) struct IClass *cl,
REG(a2) Object *obj,
REG(a1) Msg msg)
{
// ...
}
Compiling and linking with SAS-C can look like this:
Myclass.mcc: Myclass.c
sc $(CFLAGS) $*.c OBJNAME $*.o
slink to $@ from $*.o lib $(LINKERLIBS) $(LINKERFLAGS)
Note well that we don't use SAS library creation feature here, it simply
sucks too much. It's not much more complicated to do the library
initialziation ourselves and we have better control over everything.
Make sure to read the whole source to get some interesting comments
and some understanding on how libraries are created!
*****************************************************************************/
/* a few includes... */
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/libraries.h>
#include <exec/semaphores.h>
#include <exec/resident.h>
#include <dos/dos.h>
#include <clib/exec_protos.h>
#include <pragmas/exec_sysbase_pragmas.h>
/* The name of the class will also become the name of the library. */
/* We need a pointer to this string in our ROMTag (see below). */
static const char UserLibName[] = CLASS;
/* Here's our global data, described above. */
struct Library *MUIClassBase;
struct Library *MUIMasterBase;
struct Library *SysBase;
struct Library *UtilityBase;
struct Library *DOSBase;
struct Library *GfxBase;
struct Library *IntuitionBase;
#ifdef SUPERCLASS
struct MUI_CustomClass *ThisClass;
#endif
#ifdef SUPERCLASSP
struct MUI_CustomClass *ThisClassP;
#endif
#ifdef _DCC
#define REG(x) __ ## x
#define ASM
#define SAVEDS __geta4
#else
#define REG(x) register __ ## x
#define ASM __asm
#define SAVEDS __saveds
#endif
/* Our library structure, consisting of a struct Library, a segment pointer */
/* and a semaphore. We need the semaphore to protect init/exit stuff in our */
/* open/close functions */
struct LibraryHeader
{
struct Library lh_Library;
BPTR lh_Segment;
struct SignalSemaphore lh_Semaphore;
};
/* Prototypes for all library functions */
struct LibraryHeader * ASM LibInit (REG(a0) BPTR Segment);
BPTR ASM LibExpunge(REG(a6) struct LibraryHeader *base);
struct LibraryHeader * ASM LibOpen (REG(a6) struct LibraryHeader *base);
BPTR ASM LibClose (REG(a6) struct LibraryHeader *base);
LONG ASM LibNull (VOID);
ULONG SAVEDS ASM MCC_Query (REG(d0) LONG which);
/* Prototypes for a few sub-functions */
BOOL ASM UserLibInit (REG(a6) struct Library *base);
BOOL ASM UserLibExpunge(REG(a6) struct Library *base);
BOOL ASM UserLibOpen (REG(a6) struct Library *base);
BOOL ASM UserLibClose (REG(a6) struct Library *base);
/* This is the librarie's jump table */
static const APTR LibVectors[] =
{
LibOpen,
LibClose,
LibExpunge,
LibNull,
MCC_Query,
(APTR)-1
};
/* Dummy entry point and LibNull() function all in one */
LONG ASM LibNull(VOID)
{
return(NULL);
}
/* Here's what makes us a library. */
static const struct Resident ROMTag =
{
RTC_MATCHWORD,
&ROMTag,
&ROMTag + 1,
0,
VERSION,
NT_LIBRARY,
0,
UserLibName,
UserLibID,
LibInit
};
#undef D
#undef bug
#undef bugg
#ifdef DEBUG
#ifndef __KMEL
extern void kprintf(const char *, ...);
#endif
#define D(flags,x) { ##x; }
#define bug kprintf("%-12.12s %-17.17s: ",__FILE__,__FUNC__); kprintf
#define bugg kprintf
#else
#define D(flags,x)
#define bug
#define bugg
#endif /* DEBUG */
/******************************************************************************/
/* Standard Library Functions, all of them are called in Forbid() state. */
/******************************************************************************/
struct LibraryHeader * ASM SAVEDS LibInit(REG(a0) BPTR Segment)
{
struct LibraryHeader *base;
SysBase = *((struct Library **)4);
D(DBF_LIB,bug("start...\n"));
#ifdef __SASC
#ifdef _M68040
if (!(((struct ExecBase *)SysBase)->AttnFlags & AFF_68040)) return(NULL);
#endif
#ifdef _M68030
if (!(((struct ExecBase *)SysBase)->AttnFlags & AFF_68030)) return(NULL);
#endif
#ifdef _M68020
if (!(((struct ExecBase *)SysBase)->AttnFlags & AFF_68020)) return(NULL);
#endif
#endif
if (base = (struct LibraryHeader *)MakeLibrary((APTR)LibVectors,NULL,NULL,sizeof(struct LibraryHeader),NULL))
{
base->lh_Library.lib_Node.ln_Type = NT_LIBRARY;
base->lh_Library.lib_Node.ln_Name = (char *)UserLibName;
base->lh_Library.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
base->lh_Library.lib_Version = VERSION;
base->lh_Library.lib_Revision = REVISION;
base->lh_Library.lib_IdString = (char *)UserLibID;
base->lh_Segment = Segment;
InitSemaphore(&base->lh_Semaphore);
AddLibrary((struct Library *)base);
}
else
{
D(DBF_LIB,bug("\7MakeLibrary() failed\n"));
}
return(base);
}
BPTR ASM SAVEDS LibExpunge(REG(a6) struct LibraryHeader *base)
{
struct Library *SysBase = *((struct Library **)4);
BPTR rc;
D(DBF_LIB,bug("OpenCount=%ld\n",base->lh_Library.lib_OpenCnt));
if (base->lh_Library.lib_OpenCnt)
{
base->lh_Library.lib_Flags |= LIBF_DELEXP;
D(DBF_LIB,bug("Setting LIBF_DELEXP\n"));
return(NULL);
}
Remove((struct Node *)base);
rc = base->lh_Segment;
FreeMem((BYTE *)base - base->lh_Library.lib_NegSize,base->lh_Library.lib_NegSize + base->lh_Library.lib_PosSize);
return(rc);
}
struct LibraryHeader * ASM SAVEDS LibOpen(REG(a6) struct LibraryHeader *base)
{
struct Library *SysBase = *((struct Library **)4);
struct LibraryHeader *rc;
base->lh_Library.lib_OpenCnt++;
base->lh_Library.lib_Flags &= ~LIBF_DELEXP;
D(DBF_LIB,bug("OpenCount=%ld\n",base->lh_Library.lib_OpenCnt));
ObtainSemaphore(&base->lh_Semaphore);
if (UserLibOpen((struct Library *)base))
{
rc = base;
}
else
{
rc = NULL;
base->lh_Library.lib_OpenCnt--;
D(DBF_LIB,bug("\7UserLibOpen() failed\n"));
}
ReleaseSemaphore(&base->lh_Semaphore);
return(rc);
}
BPTR ASM SAVEDS LibClose(REG(a6) struct LibraryHeader *base)
{
struct Library *SysBase = *((struct Library **)4);
BPTR rc = NULL;
D(DBF_LIB,bug("OpenCount=%ld %s\n",base->lh_Library.lib_OpenCnt,base->lh_Library.lib_OpenCnt==0 ? "\7ERROR" : ""));
ObtainSemaphore(&base->lh_Semaphore);
UserLibClose((struct Library *)base);
ReleaseSemaphore(&base->lh_Semaphore);
if (--base->lh_Library.lib_OpenCnt == 0)
{
if (base->lh_Library.lib_Flags & LIBF_DELEXP)
{
rc = LibExpunge(base);
}
}
return(rc);
}
BOOL ASM SAVEDS UserLibOpen(REG(a6) struct Library *base)
{
ULONG ASM _Dispatcher(REG(a0) struct IClass *cl, REG(a2) Object *obj, REG(a1) Msg msg);
ULONG ASM _DispatcherP(REG(a0) struct IClass *cl, REG(a2) Object *obj, REG(a1) Msg msg);
BOOL ClassInitFunc(struct Library *base);
D(DBF_CLASS,bug("%ld\n",base->lib_OpenCnt));
if (base->lib_OpenCnt!=1)
return(TRUE);
#ifndef MASTERVERSION
#define MASTERVERSION MUIMASTER_VMIN
#endif
if (MUIMasterBase = OpenLibrary("muimaster.library",MASTERVERSION))
{
#ifdef SUPERCLASS
if (ThisClass = MUI_CreateCustomClass(base,SUPERCLASS,NULL,sizeof(struct Data),_Dispatcher))
#endif
{
#ifdef SUPERCLASSP
if (ThisClassP = MUI_CreateCustomClass(base,SUPERCLASSP,NULL,sizeof(struct DataP),_DispatcherP))
#endif
{
#ifdef SUPERCLASS
#define THISCLASS ThisClass
#else
#define THISCLASS ThisClassP
#endif
UtilityBase = THISCLASS->mcc_UtilityBase;
DOSBase = THISCLASS->mcc_DOSBase;
GfxBase = THISCLASS->mcc_GfxBase;
IntuitionBase = THISCLASS->mcc_IntuitionBase;
#ifndef ClassInit
return(TRUE);
#else
if (ClassInitFunc(base))
{
return(TRUE);
}
#ifdef SUPERCLASSP
MUI_DeleteCustomClass(ThisClassP);
ThisClassP = NULL;
#endif
#endif
}
#ifdef SUPERCLASSP
#ifdef SUPERCLASS
MUI_DeleteCustomClass(ThisClass);
ThisClass = NULL;
#endif
#endif
}
CloseLibrary(MUIMasterBase);
MUIMasterBase = NULL;
}
D(DBF_CLASS,bug("fail.: %08lx %s\n",base,base->lib_Node.ln_Name));
return(FALSE);
}
BOOL ASM SAVEDS UserLibClose(REG(a6) struct Library *base)
{
VOID ClassExitFunc(struct Library *base);
D(DBF_CLASS,bug("%ld\n",base->lib_OpenCnt));
if (base->lib_OpenCnt==1)
{
#ifdef ClassExit
ClassExitFunc(base);
#endif
#ifdef SUPERCLASSP
if (ThisClassP)
{
MUI_DeleteCustomClass(ThisClassP);
ThisClassP = NULL;
}
#endif
#ifdef SUPERCLASS
if (ThisClass)
{
MUI_DeleteCustomClass(ThisClass);
ThisClass = NULL;
}
#endif
if (MUIMasterBase)
{
CloseLibrary(MUIMasterBase);
MUIMasterBase = NULL;
}
}
return(TRUE);
}
ULONG SAVEDS ASM MCC_Query(REG(d0) LONG which)
{
switch (which)
{
#ifdef SUPERCLASS
case 0: return((ULONG)ThisClass);
#endif
#ifdef SUPERCLASSP
case 1: return((ULONG)ThisClassP);
#endif
#ifdef PREFSIMAGEOBJECT
case 2:
{
Object *obj = PREFSIMAGEOBJECT;
return((ULONG)obj);
}
#endif
#ifdef ONLYGLOBAL
case 3:
{
return(TRUE);
}
#endif
}
return(NULL);
}